module S_send
(
    input                I_clk           , // 主机输入时钟
    input                I_rst_n         , // 系统全局复位
    input                I_iic_send_en   , // IIC发送使能位
    
    input        [6:0]   I_dev_addr      , // 从设备的物理地址
    input        [7:0]   I_word_addr     , // 从设备的字地址
    input        [7:0]   I_write_data    , // 往主设备的字地址写入的数据
    output               O_done_flag     , // 读或写IIC设备结束标志位
    
	 output       [7:0]   S_read_data_reg , // 测试从机是否接收到数据
	 
	 output               O_sda           , // 从向主输出SDA线
	 input                I_sda             // 主向从输入SDA线
	 
	 
);          

 
reg     [3:0]   R_state         ; 
reg             R_sda_mode      ; // 设置SDA模式，1位输出，0为输入
reg             R_sda_reg       ; // SDA寄存器
reg     [7:0]   R_load_data     ; // 发送/接收过程中加载的数据，比如设备物理地址，字地址和数据等
reg     [3:0]   R_bit_cnt       ; // 发送字节状态中bit个数计数
reg             R_ack_flag      ; // 应答标志
reg     [3:0]   R_jump_state    ; // 跳转状态，传输一个字节成功并应答以后通过这个变量跳转到导入下一个数据的状态
reg     [7:0]   R_read_data_reg ; // 接收数据寄存器
reg             R_flag          ; 




assign  O_sda  =  (R_sda_mode == 1'b1) ? R_sda_reg : 1'bz ;

assign  S_read_data_reg = R_read_data_reg ;
assign  O_done_flag     =  R_flag     ;


always @(I_clk or I_rst_n)  // posedge I_clk or negedge I_rst_n
begin
    if(!I_rst_n)
        begin
            R_state         <=  4'd0 ;
            R_sda_mode      <=  1'b0 ; // 设置SDA为输入，以此来关闭此时的SDA输出线
            R_sda_reg       <=  1'b1 ;
            R_bit_cnt       <=  4'd0 ;
            R_flag          <=  1'b0 ;
            R_jump_state    <=  4'd0 ;
            R_ack_flag      <=  1'b0 ;
				R_read_data_reg <=  8'd0 ; //////////
        end
    else if(I_iic_send_en) // 往IIC设备发送数据
        begin
            case(R_state)
                4'd0   : // 空闲状态设置SCL与SDA均为高，持续等待主机起始信号
                    begin
                        R_sda_mode      <=  1'b0 ; // 设置SDA为输入，以此来关闭此时的SDA输出线
                        R_sda_reg       <=  1'b1 ; // 设置SDA为高电平
								R_bit_cnt       <=  4'd0 ; // 发送字节状态中bit个数计数清零
                        R_flag          <=  1'b0 ;
                        R_jump_state    <=  4'd0 ;
								R_read_data_reg <=  8'd0 ;
                        //
								if(I_clk == 1'b1) 
								    begin
								        if(I_sda == 1'b0)  // 识别起始信号
								            begin
									             R_state     <=  4'd1 ; // 下一个状态是接收主机广发的从机地址
									         end
										  else
										      R_state     <=  4'd0 ; //如果等不到起始信号则在0状态等待
							       end
								else
								    R_state     <=  4'd0 ; //如果等不到起始信号则在0状态等待
                    end                               
                4'd1   :  // 接收主机广发的从机物理地址/寄存器地址              
                    begin                             
                        R_sda_mode  <=  1'b0 ; // 设置SDA的模式为输入
                        if(I_clk == 1'b1)
                            begin
                                if(R_bit_cnt == 4'd8)
                                    begin
                                        R_bit_cnt    <=  4'd0    ; // 此处原本接状态4'd2，为了让应答及时发出，调整了一次时序						  
                                        if(R_read_data_reg[7:1] == I_dev_addr)
								                    begin
								                        R_state      <=  4'd3  ;										                       
									                     if(R_read_data_reg[0] == 1'b0)
									                         R_jump_state <=  4'd1  ;
								                        else if(R_read_data_reg[0] == 1'b1)
									                         R_jump_state <=  4'd4  ;
																	 R_load_data <=  I_write_data ; 
								                    end
							                   else if(R_read_data_reg[7:0] == I_word_addr)
								                    begin
								                        R_state         <=  4'd3  ;								  
                                                R_jump_state    <=  4'd2  ; //  R_jump_state    <=  4'd0;
									                 end
							                   else   
													     begin
								                    R_state      <=  4'd8 ; // 转入8状态
														  end
                                    end
                                else
                                    begin
                                        R_read_data_reg  <=  {R_read_data_reg[6:0],I_sda}  ; // 从高位接收，接7位地址加最低一位方向位
                                        R_bit_cnt        <=  R_bit_cnt   +   1'b1          ; 
                                    end    
                            end 
                        else
                            R_state <=  4'd1 ; // 循环等待主机广发的从机物理地址   
                    end                                     
                4'd2   :    // 为第二次发送起始位和物理地址，空出一个周期                    
                    begin
						      if(I_clk == 1'b0)
                            R_state <= 4'd2;
							   else if(I_clk == 1'b1)
								    R_state <= 4'd0;
                    end 
					 4'd3   :   // 发送应答                     
                    begin
                        //R_sda_mode  <=  1'b1 ; // 设置SDA的模式为输出
                        if(I_clk == 1'b0)
                            begin
									     R_sda_mode  <=  1'b1 ; 
                                R_sda_reg   <=  1'b0 ;										  
                            end 
                        else
                            R_state <=  R_jump_state ; 						  

                    end                                                   
                4'd4   :    // 发送被选中的寄存器要发送的数据                   
                    begin                                   
                        R_sda_mode  <=  1'b1                ; // 设置SDA为输出
                        if(I_clk == 1'b0)
                            begin
                                if(R_bit_cnt == 4'd8)
                                    begin
                                        R_bit_cnt   <=  4'd0            ;
                                        R_state     <=  4'd5            ; // 字节发完以后进入等待主机应答状态
                                    end
                                else
                                    begin                                 
                                        R_sda_reg   <=  R_load_data[7-R_bit_cnt] ; // 先发送高位
                                        R_bit_cnt   <=  R_bit_cnt + 1'b1         ; 
                                    end
                            end
                        else
                            R_state <=  4'd4 ; // 字节没发完时在这个状态一直等待                          
                    end
                4'd5   :    // 等待主机应答
                    begin
                        R_sda_mode  <=  1'b0                ; // 设置SDA为输入
                        if(I_clk == 1'b1)
                            begin
                                R_ack_flag  <=  I_sda  ; 
                                R_state     <=  4'd6   ; 
                            end                            
                        else
                            R_state <=  4'd5 ; // 字节没发完时在这个状态一直等待 
                    end 
                4'd6   :    // 校验主机发送的应答位
                    begin                      
                        if(R_ack_flag == 1'b0)    // 校验通过(有没有可能是无应答信号产生导致其为0)
                            begin
                                R_state  <=  R_jump_state ; // 此时R_jump_state是4'd4,此处保留了循环发送的可能
                            end
                        else if(R_ack_flag == 1'b1)
                            R_state <=  4'd7 ;     
                    end
                4'd7  :    // 接收停止信号
                    begin                      
                        if(I_clk == 1'b1)    // 校验通过
                            begin
                                if(I_sda == 1'b1) 
                                    R_state <= 4'd8    ;
                                else
                                    R_state <= 4'd7    ;
                            end
                        else
                            R_state <=  4'd7 ;      
                    end
                4'd8   : // 从机写操作结束
                    begin
                        R_sda_mode  <=  1'b0 ; // 设置SDA为输出
                        R_sda_reg   <=  1'b1 ; // 拉高SDA保持空闲状态情况
                        R_flag      <=  1'b1 ; // 停止，操作完全结束
                        R_state     <=  4'd0 ; 
                        R_ack_flag  <=  1'b0 ;
                    end
                default    : R_state     <=  4'd0 ; 
            endcase
        end 
    else
        begin
            R_state         <=  4'd0 ;
            R_sda_mode      <=  1'b0 ; //设置SDA为输入，以此来关闭此时的SDA输出线
            R_sda_reg       <=  1'b1 ;
            R_bit_cnt       <=  4'd0 ;
            R_flag          <=  1'b0 ;
            R_jump_state    <=  4'd0 ;
            R_ack_flag      <=  1'b0 ;
        end
end
endmodule